/*
 * @Author: your name
 * @Date: 2021-09-08 09:33:33
 * @LastEditTime: 2021-09-15 10:17:37
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \web-maps\src\util\mdfs\binary11\binary11Parser.ts
 */

import BinaryReader from "../BinaryReader";

export interface Binary11Info {
  mdfs: string;
  type: number;
  modelName: string;
  element: string;
  description: string;
  level: number;
  year: number;
  month: number;
  day: number;
  hour: number;
  timezone: number;
  period: number;
  startLon: number;
  endLon: number;
  xInterval: number;
  numLon: number;
  startLat: number;
  endLat: number;
  yInterval: number;
  numLat: number;
  startValue: number;
  endValue: number;
  lineInterval: number;
}

export interface Binary11Data {
  position: [number, number];
  speed: number;
  angle: number;
}

export interface Binary11StreamData {
  data: Array<Array<Binary11Data>>;
  info: Binary11Info;
}

export interface Binary11VacuateStreamData extends Binary11StreamData {
  orgData: Array<Array<Binary11Data>>
}

export default class binary11Parser extends BinaryReader {
  private info!: Binary11Info;

  private streamData!: Array<Array<Binary11Data>>;

  constructor(arrayBuffer: ArrayBuffer) {
    super(new DataView(arrayBuffer));
  }

  private headerInfo() {
    const info = {} as Binary11Info;
    info.mdfs = this.replaceEnd(this.ReadChars(4));
    info.type = this.ReadInt16();
    info.modelName = this.replaceEnd(this.ReadChars(20));
    info.element = this.replaceEnd(this.ReadChars(50));
    info.description = this.replaceEnd(this.ReadChars(30));
    info.level = this.ReadFloat32();
    info.year = this.ReadInt32();
    info.month = this.ReadInt32();
    info.day = this.ReadInt32();
    info.hour = this.ReadInt32();
    info.timezone = this.ReadInt32();
    info.period = this.ReadInt32();

    info.startLon = this.ReadFloat32();
    info.endLon = this.ReadFloat32();
    info.xInterval = this.ReadFloat32();
    info.numLon = this.ReadInt32();
    info.startLat = this.ReadFloat32();
    info.endLat = this.ReadFloat32();
    info.yInterval = this.ReadFloat32();
    info.numLat = this.ReadInt32();

    info.startValue = this.ReadFloat32();
    info.endValue = this.ReadFloat32();
    info.lineInterval = this.ReadFloat32();

    this.info = info;

    return this.info;
  }

  private vectorData() {
    const {
      numLon,
      numLat,
      yInterval,
      xInterval,
      startLon,
      startLat,
    } = this.info;

    const streamData: Array<Array<Binary11Data>> = [];
    let extent = this.ReadBytes(100);

    let count = extent[2];

    if (count === 0) count = 1;

    const size = numLat * numLon;

    let speed = this.ReadBytes(size * 4);
    let angle = this.ReadBytes(size * 4);

    for (let i = 0; i < count; i++) {
      if (i > 0) {
        extent = this.ReadBytes(278);
        const speed1 = this.ReadBytes(size * 4);
        const angle1 = this.ReadBytes(size * 4);

        if (speed1.byteLength != 0) speed = speed1;
        if (angle1.byteLength != 0) angle = angle1;
      }
    }

    const d_speed = new DataView(speed.buffer);
    const d_angle = new DataView(angle.buffer);

    for (let j = 1; j <= count; j++) {
      const data: Array<Binary11Data> = [];

      for (let l = 0; l < numLat; l++) {
        const _lat = l * yInterval + startLat;

        for (let n = 0; n < numLon; n++) {
          const _long = n * xInterval + startLon;
          const offset = (l * numLon + n) * 4;
          const _speed = d_speed.getFloat32(offset, true);
          let _angle = d_angle.getFloat32(offset, true);

          //cassandra数据,西风为0°，逆时针
          //渲染时，南风为0°，顺时针
          _angle = 270.0 - _angle;
          if (_angle < 0) {
            _angle += 360;
          }

          data.push({
            position: [_long, _lat],
            speed: _speed,
            angle: _angle,
          });
        }
      }

      streamData.push(data);
    }

    this.streamData = streamData;

    return streamData;
  }

  Parser(): Binary11StreamData {
    this.headerInfo();

    return {
      info: this.info,
      data: this.vectorData(),
    };
  }

  /**
   * @description 按照步长抽稀数据
   * @param interval 格距
   */
  vacuateData(interval:number): Binary11VacuateStreamData {

    const { numLat, numLon, xInterval } = this.info;
    const step = interval === xInterval ? 0 : Math.round(interval / xInterval);

    let newStreamDataList: Array<Array<Binary11Data>> = [];

    for (const data of this.streamData) {
      const streamData: Array<Binary11Data> = [];
      for (let i = 0; i < numLat; i++) {
        for (let j = 0; j < numLon; j++) {
          const index = i * numLon + j;
          if (i % step === 0 && j % step === 0) {
            streamData.push(data[index]);
          }
        }
      }
      newStreamDataList.push(streamData);
    }

    return {
      data: newStreamDataList,
      orgData:this.streamData,
      info: this.info,
    };
  }
}
